package com.example.java_gobang.game;

import com.example.java_gobang.JavaGobangApplication;
import com.example.java_gobang.model.User;
import com.example.java_gobang.model.UserMapper;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.Data;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;

import java.io.IOException;
import java.util.UUID;

// 表示一个游戏房间
@Data
public class Room {
    private String roomId;

    private User user1;
    private User user2;

    // 先手方玩家 id
    private int whiteUser;

    private static final int MAX_ROW = 15;
    private static final int MAX_COL = 15;

    // 表示棋盘
    // 0 表示未落子，使用 1，2 表示用户 1，2 的落子位置
    private int[][] board = new int[MAX_ROW][MAX_COL];

    // 用来转换 JSON
    private ObjectMapper objectMapper = new ObjectMapper();

    // 用于查询房间中的所有用户
    //@Autowired
    private OnlineUserManger onlineUserManger;

    // 引入房间，游戏结束将其销毁
    //@Autowired
    private RoomManager roomManager;

    private UserMapper userMapper;

    public void putChess(String jsonString) throws IOException {
        // 1. 记录当前落子的位置
        GameRequest request = objectMapper.readValue(jsonString, GameRequest.class);
        GameResponse response = new GameResponse();
        // 判断当前落子用户是谁
        int chess = request.getUserId() == user1.getUserId() ? 1 : 2;
        int row = request.getRow();
        int col = request.getCol();
        if(board[row][col] != 0){
            // 重复落子的处理
            System.out.println("当前位置 (" + row + ", " + col + ") 已经有子了");
            return;
        }

        board[row][col] = chess;

        // 打印当前棋盘的信息
        printBoard();

        // 2. 进行胜负判定
        int winner = checkWinner(row, col, chess);
        // 3. 给客户端返回响应(返回给所有人)
        response.setMessage("putChess");
        response.setUserId(request.getUserId());
        response.setRow(row);
        response.setCol(col);
        response.setWinner(winner);

        // 先获取到用户的 WebSocketSession, 给用户发送 websocket 数据
        WebSocketSession session1 = onlineUserManger.getFromGameRoom(user1.getUserId());
        WebSocketSession session2 = onlineUserManger.getFromGameRoom(user2.getUserId());

        // 若有一方会话为空(玩家下线),则判定另一方获胜
        if (session1 == null){
            response.setWinner(user2.getUserId());
            System.out.println("玩家1 掉线！");
        }
        if (session2 == null){
            response.setWinner(user1.getUserId());
            System.out.println("玩家2 掉线！");
        }
        // 把响应构造为 JSON 字符串，通过 session 进行传输
        String respJson = objectMapper.writeValueAsString(response);
        if(session1 != null){
            session1.sendMessage(new TextMessage(respJson));
        }
        if(session2 != null){
            session2.sendMessage(new TextMessage(respJson));
        }

        // 若有人获胜，就销毁房间
        if(response.getWinner() != 0){
            System.out.println("游戏结束，房间 " + roomId + "关闭");
            // 结算分数
            int winUserId = response.getWinner();
            int loseUserId = response.getWinner() == user1.getUserId() ? user2.getUserId() : user1.getUserId();
            userMapper.userWin(winUserId);
            userMapper.userLose(loseUserId);
            // 销毁房间
            roomManager.remove(roomId,user1.getUserId(),user2.getUserId());
        }

    }

    private void printBoard() {
        // 打印棋盘
        System.out.println("【棋盘信息】 " + roomId);
        System.out.println("=============================");
        for (int r = 0; r < MAX_ROW; r++){
            for (int c = 0; c < MAX_COL; c++){
                System.out.print(board[r][c] + " ");
            }
            // 换行
            System.out.println();
        }
        System.out.println("=============================");
    }

    // 此方法用于判断胜负
    // 返回获胜方的用户 id, 未分胜负就返回 0;
    private int checkWinner(int row, int col, int chess) {
        // 1. 检测所有行(五种情况)
        for (int c = col - 4; c <= col; c++){
            try {
                if(board[row][c] == chess
                        && board[row][c+1] == chess
                        && board[row][c+2] == chess
                        && board[row][c+3] == chess
                        && board[row][c+4] == chess) {

                    return chess == 1 ? user1.getUserId() : user2.getUserId();
                }
            }catch (ArrayIndexOutOfBoundsException e){
                continue;
            }
        }

        // 2. 检查所有列
        for (int r = row - 4; r <= row; r++){
            try {
                if(board[r][col] == chess
                    && board[r+1][col] == chess
                    && board[r+2][col] == chess
                    && board[r+3][col] == chess
                    && board[r+4][col] == chess){

                    return chess == 1 ? user1.getUserId() : user2.getUserId();
                }
            }catch (ArrayIndexOutOfBoundsException e){
                continue;
            }
        }

        // 3. 检查左对角线
        for (int r = row - 4, c = col - 4; r <= row && c <= col; r++, c++){
            try {
                if(board[r][c] == chess
                    && board[r+1][c+1] == chess
                    && board[r+2][c+2] == chess
                    && board[r+3][c+3] == chess
                    && board[r+4][c+4] == chess){

                    return chess == 1 ? user1.getUserId() : user2.getUserId();
                }
            }catch (ArrayIndexOutOfBoundsException e){
                continue;
            }
        }

        // 4. 检查右对角线
        for (int r = row - 4, c = col + 4; r <= row && c >= col; r++, c--){
            try {
                if(board[r][c] == chess
                        && board[r+1][c-1] == chess
                        && board[r+2][c-2] == chess
                        && board[r+3][c-3] == chess
                        && board[r+4][c-4] == chess){

                    return chess == 1 ? user1.getUserId() : user2.getUserId();
                }
            }catch (ArrayIndexOutOfBoundsException e ){
                continue;
            }
        }
        return 0;
    }

    public Room() {
        // 构造 Room 时使用 UUID 生成唯一的字符串表示房间 id;
        roomId = UUID.randomUUID().toString();
        // 通过入口类中记录的 context 来手动获取到前面的 RoomManager 和 OnlineUserManger;
        onlineUserManger = JavaGobangApplication.context.getBean(OnlineUserManger.class);
        roomManager = JavaGobangApplication.context.getBean(RoomManager.class);
        userMapper = JavaGobangApplication.context.getBean(UserMapper.class);
    }

    public static void main(String[] args){
        Room room = new Room();
        System.out.println(room.roomId);
    }
}
